#pragma once

#include "market_data.h"
#include <ThostFtdcMdApi.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <atomic>
#include <memory>

namespace hft {

/**
 * @defgroup market_data Market Data Module
 * @brief 市场数据接收和处理模块
 */

/**
 * @class CtpMarketDataReceiver
 * @brief CTP行情数据接收器实现
 * @ingroup market_data
 *
 * 该类实现了基于CTP API的市场数据接收功能，提供:
 * - 实时行情订阅
 * - 历史数据查询
 * - 行情数据转换
 * 
 * @note 使用前必须调用init()方法进行初始化
 * @warning 非线程安全方法需要外部加锁
 */
class CtpMarketDataReceiver : public MarketDataProvider {
public:
    CtpMarketDataReceiver();
    ~CtpMarketDataReceiver() override;

    /**
     * @brief 初始化CTP行情接收器
     * 
     * @param config YAML配置节点，包含以下必需字段:
     *   - front_address: CTP前置地址
     *   - user_id: 用户名
     *   - password: 密码
     *   - broker_id: 经纪商代码
     *   - app_id: 应用标识(可选)
     *   - auth_code: 认证码(可选)
     * 
     * @return bool 初始化是否成功
     * @retval true 初始化成功
     * @retval false 初始化失败
     * 
     * @throw std::invalid_argument 当缺少必需配置字段时抛出
     * @note 必须在调用其他方法前执行
     */
    bool init(const YAML::Node& config) override;

    /**
     * @brief 启动行情接收服务
     * 
     * @return bool 启动是否成功
     * @retval true 启动成功
     * @retval false 启动失败(可能未初始化或网络问题)
     * 
     * @note 调用此方法后会连接CTP前置并开始接收行情
     * @warning 重复调用可能导致未定义行为
     */
    bool start() override;

    /**
     * @brief 停止行情接收服务
     * 
     * @note 调用此方法后会断开CTP连接并停止所有行情接收
     * @warning 停止后需要重新调用start()才能恢复服务
     */
    void stop() override;

    /**
     * @brief 订阅单个合约的行情数据
     * 
     * @param symbol 合约代码，格式为交易所代码.合约代码(如"SHFE.cu2305")
     * 
     * @return bool 订阅是否成功
     * @retval true 订阅请求发送成功
     * @retval false 订阅请求发送失败(可能未初始化或网络问题)
     * 
     * @note 实际订阅成功与否需要通过onSubMarketData回调确认
     * @warning 每个交易所的合约代码格式可能不同
     */
    bool subscribe(const std::string& symbol) override;
    /**
     * @brief 取消订阅单个合约的行情数据
     * 
     * @param symbol 合约代码，格式为交易所代码.合约代码(如"SHFE.cu2305")
     * 
     * @return bool 取消订阅是否成功
     * @retval true 取消订阅请求发送成功
     * @retval false 取消订阅请求发送失败(可能未初始化或网络问题)
     * 
     * @note 实际取消订阅成功与否需要通过回调确认
     * @warning 取消订阅后仍可能收到少量延迟数据
     */
    bool unsubscribe(const std::string& symbol) override;

    /**
     * @brief 获取指定合约的最新市场数据快照
     * 
     * @param symbol 合约代码，格式为交易所代码.合约代码(如"SHFE.cu2305")
     * 
     * @return MarketData 包含最新行情数据的结构体，如果合约不存在返回空结构体
     * 
     * @note 此方法是线程安全的
     * @warning 返回的数据可能有延迟，不适合用于精确计算
     * @see subscribe() 需要先订阅合约才能获取数据
     */
    MarketData getLatestMarketData(const std::string& symbol) const override;

    /**
     * @brief 获取指定合约的历史行情数据
     * 
     * @param symbol 合约代码，格式为交易所代码.合约代码(如"SHFE.cu2305")
     * @param start_time 查询开始时间点
     * @param end_time 查询结束时间点
     * 
     * @return std::vector<MarketData> 历史行情数据列表，按时间升序排列
     * 
     * @note 返回的数据量可能受内存限制
     * @warning 时间范围过大可能导致性能问题
     * @see subscribe() 需要先订阅合约才能获取数据
     */
    std::vector<MarketData> getHistoricalMarketData(
        const std::string& symbol,
        const std::chrono::system_clock::time_point& start_time,
        const std::chrono::system_clock::time_point& end_time
    ) const override;

private:
    // CTP回调处理
    class CtpCallback : public CThostFtdcMdSpi {
    public:
        explicit CtpCallback(CtpMarketDataReceiver* receiver);
        ~CtpCallback() override = default;

        /**
         * @brief 与CTP前置服务器连接成功的回调
         * 
         * @note 此回调在CTP API线程中触发，非主线程
         * @warning 在此回调中不要执行耗时操作
         * @see OnRspUserLogin 连接成功后需要立即调用登录接口
         */
        void OnFrontConnected() override;
        /**
         * @brief 与CTP前置服务器连接断开的回调
         * 
         * @param reason 断开原因代码:
         *   - 0x1001 网络读失败
         *   - 0x1002 网络写失败
         *   - 0x2001 接收心跳超时
         *   - 0x2002 发送心跳失败
         *   - 0x2003 收到错误报文
         * 
         * @note 此回调在CTP API线程中触发，非主线程
         * @warning 系统不会自动重连，需要手动调用start()重连
         * @see start() 可用于重新建立连接
         */
        void OnFrontDisconnected(int reason) override;

        /**
         * @brief 用户登录请求响应回调
         * 
         * @param pRspUserLogin 用户登录响应信息，包含:
         *   - 交易日
         *   - 登录成功时间
         *   - 经纪商ID
         *   - 用户ID
         *   - 系统名称
         *   - 前置编号
         *   - 最大报单引用
         * 
         * @param pRspInfo 响应错误信息，包含:
         *   - ErrorID 错误代码
         *   - ErrorMsg 错误消息
         * 
         * @param request_id 请求ID
         * @param is_last 是否为最后一条响应
         * 
         * @note 此回调在CTP API线程中触发，非主线程
         * @warning 如果ErrorID不为0，表示登录失败
         * @see OnFrontConnected() 连接成功后需要调用登录接口
         */
        void OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin,
                          CThostFtdcRspInfoField* pRspInfo,
                          int request_id,
                          bool is_last) override;

        /**
         * @brief 行情订阅请求响应回调
         * 
         * @param pSpecificInstrument 合约信息，包含:
         *   - InstrumentID 合约代码
         * 
         * @param pRspInfo 响应错误信息，包含:
         *   - ErrorID 错误代码
         *   - ErrorMsg 错误消息
         * 
         * @param request_id 请求ID
         * @param is_last 是否为最后一条响应
         * 
         * @note 此回调在CTP API线程中触发，非主线程
         * @warning 如果ErrorID不为0，表示订阅失败
         * @see subscribe() 订阅合约的请求方法
         */
        void OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument,
                              CThostFtdcRspInfoField* pRspInfo,
                              int request_id,
                              bool is_last) override;

        /**
         * @brief 深度行情数据回调接口
         * 
         * @param pDepthMarketData 指向CTP深度行情数据结构的指针，包含:
         *   - 最新价、买卖价、成交量等
         *   - 时间戳
         *   - 合约代码等信息
         * 
         * @note 此回调在CTP API线程中触发，非主线程
         * @warning 必须快速处理此回调，避免阻塞CTP API线程
         * @see subscribe() 只有订阅的合约才会触发此回调
         */
        void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData) override;

    private:
        CtpMarketDataReceiver* receiver_;
    };

    /**
     * @brief 将CTP原始行情数据转换为内部MarketData格式
     * 
     * @param data 指向CTP深度行情数据结构的指针
     * 
     * @return MarketData 转换后的行情数据结构
     * 
     * @note 转换规则:
     *   - 时间戳转换为UTC时间
     *   - 价格单位转换为标准单位
     *   - 买卖盘数据按价格排序
     * @warning 传入空指针会导致未定义行为
     */
    MarketData convertMarketData(const CThostFtdcDepthMarketDataField* data) const;

    /**
     * @brief 将CTP合约代码转换为标准格式
     * 
     * @param instrument_id CTP原始合约代码
     * 
     * @return std::string 标准格式合约代码(交易所代码.合约代码)
     * 
     * @note 转换规则:
     *   - 根据合约前缀识别交易所
     *   - 添加交易所代码前缀
     * @warning 传入空指针会导致未定义行为
     */
    std::string convertInstrumentId(const char* instrument_id) const;

    // CTP API
    std::unique_ptr<CThostFtdcMdApi> api_;
    std::unique_ptr<CtpCallback> callback_;

    // 配置
    YAML::Node config_;
    std::string front_address_;
    std::string user_id_;
    std::string password_;
    std::string broker_id_;
    std::string app_id_;
    std::string auth_code_;

    // 行情数据
    mutable std::mutex mutex_;
    std::unordered_map<std::string, MarketData> latest_data_;
    std::unordered_map<std::string, std::vector<MarketData>> historical_data_;

    // 状态控制
    std::atomic<bool> connected_{false};
    std::atomic<bool> logged_in_{false};
};

} // namespace hft 